package com.example.mediarecorderdemo;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Bundle;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.app.ActivityCompat;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;

import com.example.mediarecorderdemo.databinding.FragmentPhotoBinding;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class PhotoFragment extends Fragment {

    private FragmentPhotoBinding mPhotoBinding;
    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();

    static {
        ORIENTATIONS.append(Surface.ROTATION_0, 90);
        ORIENTATIONS.append(Surface.ROTATION_90, 0);
        ORIENTATIONS.append(Surface.ROTATION_180, 270);
        ORIENTATIONS.append(Surface.ROTATION_270, 180);
    }

    //定义根布局管理器
    private ConstraintLayout mRootLayout;

    private AutoFitTextureView mTextureView;


    //摄像头ID 0为后置摄像1为前置摄像
    private String mCameraId = "0";
    //定义摄像头成员变量
    private CameraDevice mCameraDevice;
    //预览尺寸
    private Size mPreviewSize;
    private CaptureRequest.Builder mPreviewRequestBuilder;
    //定义预览照片的捕获请求
    private CaptureRequest mPreviewRequest;
    //定义CaptureSession变量
    private CameraCaptureSession mCameraCaptureSession;
    //定义照片工具
    private ImageReader mImageReader;
    private CameraManager mCameraManager;

    public PhotoFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        mPhotoBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_photo, container, false);
        mPhotoBinding.setLifecycleOwner(requireActivity());
        mRootLayout = mPhotoBinding.root;
        return mPhotoBinding.getRoot();
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mTextureView = new AutoFitTextureView(requireContext(), null);
        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
        mRootLayout.addView(mTextureView);

        mPhotoBinding.takePhoto.setOnClickListener(view -> {
            captureStillPicture();
        });

        mPhotoBinding.btnJump.setOnClickListener(view -> {
            NavController navController = Navigation.findNavController(view);
            navController.navigate(R.id.action_photoFragment_to_playRecordFragment);
        });
    }

    private void captureStillPicture() {
        if (mCameraDevice == null) {
            return;
        }
        //创建拍照使用的CaptureRequest.Builder
        try {
            CaptureRequest.Builder captureRequestBuilder = mCameraDevice
                    .createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            //添加imageReader的Surface作为CaptureRequest.Builder目标
            captureRequestBuilder.addTarget(mImageReader.getSurface());
            //设置自动对焦模式
            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            //设置自动曝光模式
            captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            //获取设备方向
            int rotation = requireActivity().getWindowManager().getDefaultDisplay().getRotation();
            //根据设备方向计算设置照片的方向
            captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
            //停止连续取景
            mCameraCaptureSession.stopRepeating();
            //捕获静态图像
            mCameraCaptureSession.capture(captureRequestBuilder.build(),
                    new CameraCaptureSession.CaptureCallback() {
                        @Override
                        public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                            super.onCaptureCompleted(session, request, result);
                            //重新设置对焦模式
                            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                                    CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
                            //设置自动曝光模式
                            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                            //打开连续取景模式
                            try {
                                mCameraCaptureSession.setRepeatingRequest(mPreviewRequest, null, null);
                            } catch (CameraAccessException e) {
                                e.printStackTrace();
                            }

                        }
                    }, null);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture, int width, int height) {
            //当TextureView可用是打开摄像头
            openCamera(width, height);
        }

        @Override
        public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surfaceTexture, int width, int height) {
            configureTransform(width, height);
        }

        @Override
        public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
            return true;
        }

        @Override
        public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surfaceTexture) {
        }
    };

    /**
     * 根据手机旋转方向确定预览图像的方向
     *
     * @param width  宽
     * @param height 高
     */
    private void configureTransform(int width, int height) {
        if (null == mPreviewSize) {
            return;
        }
        //获取手机旋转方向
        int rotation = requireActivity().getWindowManager().getDefaultDisplay().getRotation();
        Matrix matrix = new Matrix();
        RectF viewRectF = new RectF(0, 0, width, height);
        RectF bufferRectF = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
        float centerX = viewRectF.centerX();
        float centerY = viewRectF.centerY();
        //处理手机横屏的情况
        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
            bufferRectF.offset(centerX - bufferRectF.centerX(), centerY - bufferRectF.centerY());
            matrix.setRectToRect(viewRectF, bufferRectF, Matrix.ScaleToFit.FILL);
            float scale = Math.max(height / mPreviewSize.getHeight(), width / mPreviewSize.getWidth());
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(90 * (rotation - 2), centerX, centerY);
        } else if (Surface.ROTATION_180 == rotation) {
            //处理倒置情况
            matrix.postRotate(180, centerX, centerY);
        }
        mTextureView.setTransform(matrix);
    }

    private void openCamera(int width, int height) {
        mCameraManager = (CameraManager) requireActivity().getSystemService(Context.CAMERA_SERVICE);
        setUpCameraOutputs(width, height);
        configureTransform(width, height);
        if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        try {
            mCameraManager.openCamera(mCameraId, mStateCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void setUpCameraOutputs(int width, int height) {
        //获取指定摄像头的特性
        try {
            CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(mCameraId);
            //获取摄像头支持的配置属性
            StreamConfigurationMap configurationMap =
                    characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            //获取摄像头支持的最大尺寸
            Size largest = Collections.max(
                    Arrays.asList(configurationMap.getOutputSizes(ImageFormat.JPEG)),
                    new CompareSizeByArea()
            );
            mImageReader = ImageReader.newInstance(largest.getWidth(),
                    largest.getHeight(), ImageFormat.JPEG, 2);
            mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
                @Override
                public void onImageAvailable(ImageReader imageReader) {
                    //当照片数据可用时激发该方法
                    //获取捕获的照片数据
                    Image image = imageReader.acquireLatestImage();
                    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                    byte[] bytes = new byte[buffer.remaining()];
                    //使用IO流将照片写入指定文件
                    File file = new File(requireActivity().getExternalFilesDir(""), "pic.jpg");
                    buffer.get(bytes);
                    try {
                        FileOutputStream outputStream = new FileOutputStream(file);
                        outputStream.write(bytes);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        //释放资源
                        image.close();
                    }
                }
            }, null);
            //获取最佳预览尺寸
            mPreviewSize = chooseOptimalSize(configurationMap.getOutputSizes(SurfaceTexture.class),
                    width, height, largest);
            //根据选中的预览尺寸来调整预览组件TextureView的宽高
            int orientation = getResources().getConfiguration().orientation;
            if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
                mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            } else {
                mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private Size chooseOptimalSize(Size[] outputSizes, int width, int height, Size largest) {
        //收集摄像头支持的大过预览Surface的分辨率
        List<Size> bigEnough = new ArrayList<>();
        int w = largest.getWidth();
        int h = largest.getHeight();
        for (Size outputSize : outputSizes) {
            if (outputSize.getHeight() == outputSize.getWidth() * h / w &&
                    outputSize.getWidth() >= width && outputSize.getHeight() >= height) {
                bigEnough.add(outputSize);
            }
        }
        //如果找到多个预览尺寸，获取最小的那个
        if (bigEnough.size() > 0) {
            return Collections.min(bigEnough, new CompareSizeByArea());
        } else {
            return outputSizes[0];
        }
    }

    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice cameraDevice) {
            mCameraDevice = cameraDevice;
            //开始预览
            createCameraPreviewSession();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            cameraDevice.close();
            mCameraDevice = null;
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int error) {
            cameraDevice.close();
            mCameraDevice = null;
            requireActivity().finish();
        }
    };

    private void createCameraPreviewSession() {
        SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
        surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        Surface surface = new Surface(surfaceTexture);

        //创建预览CaptureRequest.Builder
        try {
            mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            //将textureView的Surface作为CaptureRequest.Builder的目标
            mPreviewRequestBuilder.addTarget(new Surface(surfaceTexture));

            mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                    //如果摄像头为null，直接结束
                    if (null == mCameraDevice) {
                        return;
                    }
                    //当摄像头已经准备好开始显示预览
                    mCameraCaptureSession = cameraCaptureSession;
                    //设置自动对焦模式
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                            CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                    //设置自动曝光模式
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                            CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                    //开始显示预览
                    mPreviewRequest = mPreviewRequestBuilder.build();
                    try {
                        mCameraCaptureSession.setRepeatingRequest(mPreviewRequest, null, null);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                    Toast.makeText(requireContext(), "配置失败", Toast.LENGTH_SHORT).show();
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 定义一个比较器
     */
    private class CompareSizeByArea implements Comparator<Size> {
        @Override
        public int compare(Size size, Size t1) {
            //强转long保证不会发生溢出
            return Long.signum((long) size.getWidth() * size.getHeight() - (long) t1.getWidth() * t1.getHeight());
        }
    }
}